package com.cfswt.tasksystem.controller;

import com.cfswt.tasksystem.mapper.TaskStatusMapper;
import com.cfswt.tasksystem.mapper.MaterialMapper;
import com.cfswt.tasksystem.mapper.MaterialPositionMapper;
import com.cfswt.tasksystem.pojo.dto.*;
import com.cfswt.tasksystem.pojo.entity.*;
import com.cfswt.tasksystem.pojo.vo.*;
import com.cfswt.tasksystem.response.JsonResult;
import com.cfswt.tasksystem.security.CustomUserDetails;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.activiti.api.runtime.shared.query.Page;
import org.activiti.api.runtime.shared.query.Pageable;
import org.activiti.api.task.model.Task;
import org.activiti.api.task.model.builders.TaskPayloadBuilder;
import org.activiti.api.task.runtime.TaskRuntime;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.identity.Authentication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Predicate;

@Api(tags = "20.物资管理模块")
@RestController
@RequestMapping("/material")
public class MaterialController {
    @Autowired
    private MaterialMapper materialMapper;
    @Autowired
    private TaskStatusMapper materialCategoryMapper;
    @Autowired
    private TaskRuntime taskRuntime;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private MaterialPositionMapper materialPositionMapper;
    @Autowired
    private TaskService taskService;

    @ApiOperation(value = "显示库存物资")
    @GetMapping("")
    public JsonResult showAllMaterials(@AuthenticationPrincipal CustomUserDetails userDetails) {
        List<MaterialVO> materialVOS = materialMapper.selectAllMaterialVOs();
        Boolean showPrice = userDetails.getAuthorities().stream()
                .anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals("ROLE_SHOW_PRICE"));
        if (!showPrice) {
            // 如果用户没有查看价格的权限，将价格信息设置为null
            materialVOS.forEach(materialVO -> materialVO.setUnitPriceIncludingTax(null));
        }
        System.out.println("返回给前端的数据是：" + materialVOS);
        return JsonResult.ok(materialVOS);
    }

    @ApiOperation(value = "新增物资明细")
    @PostMapping("/add")
    public JsonResult addNewMaterial(@RequestBody List<NewMaterialDTO> newMaterialDTOs) {
        for (NewMaterialDTO newMaterialDTO : newMaterialDTOs) {
            /*int categoryId = materialCategoryMapper.selectCategoryIdByName(newMaterialDTO.getCategoryName());*/
            Material material = new Material();
            material.setName(newMaterialDTO.getName()).setModel(newMaterialDTO.getModel())
                    .setUnit(newMaterialDTO.getUnit())
                    .setCategoryLargeName(newMaterialDTO.getCategoryLargeName())
                    .setCategoryLargeSn(newMaterialDTO.getCategoryLargeSn())
                    .setCategoryMediumName(newMaterialDTO.getCategoryMediumName())
                    .setCategoryMediumSn(newMaterialDTO.getCategoryMediumSn())
                    .setCategoryMiniName(newMaterialDTO.getCategoryMiniName())
                    .setCategoryMiniSn(newMaterialDTO.getCategoryMiniSn())
                    .setSn(newMaterialDTO.getSn())
                    .setCode(newMaterialDTO.getCode())
                    .setBrand(newMaterialDTO.getBrand())
                    .setReferencePrice(newMaterialDTO.getReferencePrice())
                    .setNumber(0);
            materialMapper.addNewMaterial(material);
        }
        return JsonResult.ok();
    }

    @ApiOperation(value = "提交入库申请")
    @Transactional
    @PostMapping("/warehousing")
    public JsonResult warehousing(@RequestBody WarehousingMaterialWrapper warehousingMaterialWrapper,
                                  @AuthenticationPrincipal CustomUserDetails userDetails) {
        System.out.println(warehousingMaterialWrapper);
        List<WarehousingMaterialDTO> warehousingMaterialDTOS = warehousingMaterialWrapper.getWarehousingMaterialDTOS();
        String comment = warehousingMaterialWrapper.getApprovalCommentDTO().getComment();
        String processDefinitionKey = "Process_1";
        String nickName = userDetails.getNickName();
        String businessKey = "入库申请" + nickName;
        String creator = userDetails.getUsername();
        Map<String, Object> variables = new HashMap<>();
        variables.put("creator", creator);
        LocalDate now = LocalDate.now();
        String yyMMdd = now.format(DateTimeFormatter.ofPattern("yyMMdd"));
        Integer integer = materialMapper.countWarehousingByDate(now);
        String serial = String.format("%02d", integer + 1);
        String serialNumber = "RK" + yyMMdd + serial;
        Authentication.setAuthenticatedUserId(nickName);
        String processInstanceId = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables).getProcessInstanceId();
        for (WarehousingMaterialDTO warehousingMaterialDTO : warehousingMaterialDTOS) {
            warehousingMaterialDTO.setProcessInstanceId(processInstanceId);
            int positionId = materialPositionMapper.selectPositionIdByName(warehousingMaterialDTO.getPositionName());
            warehousingMaterialDTO.setPositionId(positionId).setCreateBy(userDetails.getNickName()).setCreateTime(new Date())
                    .setSerialNumber(serialNumber).setStatus("审批中");
            materialMapper.applyWarehousing(warehousingMaterialDTO);
        }
        org.activiti.engine.task.Task userTask = taskService.createTaskQuery().processInstanceId(processInstanceId).taskAssignee(creator).singleResult();
        System.out.println("Task Name: " + userTask);
        if ("申请人填写入库单".equals(userTask.getName())) {
            if (comment != null) {
                taskService.addComment(userTask.getId(), processInstanceId, comment);
            }
            taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(userTask.getId()).build());
        }
        return JsonResult.ok();
    }

    @ApiOperation(value = "入库验收界面显示入库数据")
    @GetMapping("/warehousing/{taskId}")
    public JsonResult selectWarehousing(@PathVariable String taskId) {
        Task task = taskRuntime.task(taskId);
        String processInstanceId = task.getProcessInstanceId();
        System.out.println(processInstanceId);
        List<QualifyWarehousingVO> qualifyWarehousingVOS = materialMapper.selectQualifyWareHousingById(processInstanceId);
        System.out.println(qualifyWarehousingVOS);
        return JsonResult.ok(qualifyWarehousingVOS);
    }

    @ApiOperation(value = "入库验收")
    @Transactional
    @PostMapping("/qualify")
    public JsonResult qualifiedWarehousing(@RequestBody WarehousingMaterialWrapper warehousingMaterialWrapper,
                                           @AuthenticationPrincipal CustomUserDetails userDetails) {
        List<WarehousingMaterialDTO> warehousingMaterialDTOS = warehousingMaterialWrapper.getWarehousingMaterialDTOS();
        String comment = warehousingMaterialWrapper.getApprovalCommentDTO().getComment();
        String processInstanceId = warehousingMaterialDTOS.get(0).getProcessInstanceId();
        System.out.println(warehousingMaterialDTOS);
        for (WarehousingMaterialDTO warehousingMaterialDTO : warehousingMaterialDTOS) {
            materialMapper.updateQualifiedhousingById(warehousingMaterialDTO);
        }
        org.activiti.engine.task.Task task = taskService.createTaskQuery().taskAssignee(userDetails.getUsername()).processInstanceId(processInstanceId).singleResult();
        if ("验收".equals(task.getName())) {
            Authentication.setAuthenticatedUserId(userDetails.getNickName());
            taskService.addComment(task.getId(), processInstanceId, comment);
            taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(task.getId()).build());
        }
        return JsonResult.ok();
    }

    @ApiOperation(value = "入库保管界面显示入库数据")
    @GetMapping("/reviewWarehousing/{taskId}")
    public JsonResult selectReviewWarehousing(@PathVariable String taskId) {
        Task task = taskRuntime.task(taskId);
        String processInstanceId = task.getProcessInstanceId();
        System.out.println(processInstanceId);
        List<ReviewWarehousingVO> reviewWarehousingVOS = materialMapper.selectApplyWareHousingById(processInstanceId);
        System.out.println(reviewWarehousingVOS);
        return JsonResult.ok(reviewWarehousingVOS);
    }

    @ApiOperation(value = "保管入库")
    @Transactional
    @PostMapping("/approveWarehousing")
    public JsonResult approveWarehousing(@RequestBody WarehousingMaterialWrapper warehousingMaterialWrapper,
                                         @AuthenticationPrincipal CustomUserDetails userDetails) {
        List<WarehousingMaterialDTO> warehousingMaterialDTOS = warehousingMaterialWrapper.getWarehousingMaterialDTOS();
        String comment = warehousingMaterialWrapper.getApprovalCommentDTO().getComment();
        String processInstanceId = warehousingMaterialDTOS.get(0).getProcessInstanceId();
        for (WarehousingMaterialDTO warehousingMaterialDTO : warehousingMaterialDTOS) {
            System.out.println(warehousingMaterialDTOS);
            String serialNumber = warehousingMaterialDTO.getSerialNumber();
            System.out.println(serialNumber);
            materialMapper.updateWarehousingStatus(serialNumber, "已完成");
            materialMapper.updateCustodianhousingById(warehousingMaterialDTO);
            Material material = new Material();
            material.setCode(warehousingMaterialDTO.getCode());
            material.setTotalPriceTax(warehousingMaterialDTO.getTotalPriceTax());
            material.setTaxRate(warehousingMaterialDTO.getTaxRate());
            material.setUnitPriceBeforeTax(warehousingMaterialDTO.getUnitPriceBeforeTax());
            material.setAmountBeforeTax(warehousingMaterialDTO.getAmountBeforeTax());
            material.setNumber(warehousingMaterialDTO.getNumber());
            material.setProject(warehousingMaterialDTO.getProject());
            material.setCreateTime(warehousingMaterialDTO.getCreateTime());
            material.setCreateBy(warehousingMaterialDTO.getCreateBy());
            material.setPositionId(warehousingMaterialDTO.getPositionId());
            material.setAcceptancePerson(warehousingMaterialDTO.getAcceptancePerson());
            material.setPurchasePerson(warehousingMaterialDTO.getPurchasePerson());
            material.setCustodian(warehousingMaterialDTO.getCustodian());
            material.setReviewer(warehousingMaterialDTO.getReviewer());
            materialMapper.updateMaterialByCode(material);
        }
        Page<Task> tasks = taskRuntime.tasks(Pageable.of(0, 100), TaskPayloadBuilder.tasks()
                .withProcessInstanceId(processInstanceId)
                .withAssignee(userDetails.getUsername())
                .build());
        System.out.println(tasks);
        for (Task task : tasks.getContent()) {
            if ("保管".equals(task.getName())) {
                Authentication.setAuthenticatedUserId(userDetails.getNickName());
                taskService.addComment(task.getId(), processInstanceId, comment);
                taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(task.getId()).build());
            }
            break;
        }
        return JsonResult.ok();
    }

    @ApiOperation(value = "入库完成")
    @GetMapping("/warehousing/print/{processInstanceId}")
    public JsonResult printWarehousingList(@PathVariable String processInstanceId) {
        List<PrintWarehousingVO> printWarehousingVOS = materialMapper.selectPrintWareHousingById(processInstanceId);
        return JsonResult.ok(printWarehousingVOS);
    }

    @ApiOperation(value = "显示申请出库明细")
    @PostMapping("/selectApplyOutboundByCodes")
    public JsonResult selectOutboundByCode(@RequestBody List<Code> codes) {
        List<ApplyOutboundVO> applyOutboundVOS = materialMapper.selectApplyOutboundByCodes(codes);
        return JsonResult.ok(applyOutboundVOS);
    }
    @ApiOperation(value = "修改申请出库时根据code自动获取物资信息")
    @GetMapping("/selectApplyOutboundByCode/{code}")
    public JsonResult selectOutboundByCode(@PathVariable String code) {
        ApplyOutboundVO applyOutboundVO = materialMapper.selectApplyOutboundByCode(code);
        return JsonResult.ok(applyOutboundVO);
    }

    @ApiOperation(value = "提交出库申请")
    @Transactional
    @PostMapping("/outbound")
    public JsonResult outbound(@RequestBody OutboundMaterialWrapper outboundMaterialWrapper,
                               @AuthenticationPrincipal CustomUserDetails userDetails) {
        List<OutboundMaterialDTO> outboundMaterialDTOS = outboundMaterialWrapper.getOutboundMaterialDTOS();
        String comment = outboundMaterialWrapper.getApprovalCommentDTO().getComment();
        String processDefinitionKey = "Process_2";
        String nickName = userDetails.getNickName();
        String businessKey = "出库申请" + nickName;
        String creator = userDetails.getUsername();
        Map<String, Object> variables = new HashMap<>();
        variables.put("creator", creator);
        LocalDate now = LocalDate.now();
        String yyMMdd = now.format(DateTimeFormatter.ofPattern("yyMMdd"));
        Integer integer = materialMapper.countOutboundByDate(now);
        String serial = String.format("%02d", integer + 1);
        String serialNumber = "CK" + yyMMdd + serial;
        Authentication.setAuthenticatedUserId(nickName);
        String processInstanceId = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables).getProcessInstanceId();
        for (OutboundMaterialDTO outboundMaterialDTO : outboundMaterialDTOS) {
            outboundMaterialDTO.setProcessInstanceId(processInstanceId).setCreateBy(userDetails.getNickName())
                    .setCreateTime(new Date()).setSerialNumber(serialNumber).setStatus("审批中");
            materialMapper.applyOutbound(outboundMaterialDTO);
        }
        org.activiti.engine.task.Task userTask = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .taskAssignee(creator) // 指定任务办理人
                .singleResult();
        System.out.println("Task Name: " + userTask);
        if ("领用人发起".equals(userTask.getName())) {
            if (comment != null) {
                taskService.addComment(userTask.getId(), processInstanceId, comment);
            }
            taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(userTask.getId()).build());
        }
        return JsonResult.ok();
    }

    @ApiOperation(value = "显示审批出库明细")
    @GetMapping("/outbound/{taskId}")
    public JsonResult selectReviewOutbound(@PathVariable String taskId) {
        Task task = taskRuntime.task(taskId);
        String processInstanceId = task.getProcessInstanceId();
        System.out.println(processInstanceId);
        List<OutboundMaterialDTO> reviewOutboundData = materialMapper.selectApplyOutboundById(processInstanceId);
        System.out.println(reviewOutboundData);
        return JsonResult.ok(reviewOutboundData);
    }

    @ApiOperation(value = "出库审批")
    @Transactional
    @PostMapping("/approveOutbound")
    public JsonResult approveOutbound(@RequestBody OutboundMaterialWrapper outboundMaterialWrapper,
                                      @AuthenticationPrincipal CustomUserDetails userDetails) {
        List<OutboundMaterialDTO> outboundMaterialDTOS = outboundMaterialWrapper.getOutboundMaterialDTOS();
        String comment = outboundMaterialWrapper.getApprovalCommentDTO().getComment();
        String processInstanceId = outboundMaterialDTOS.get(0).getProcessInstanceId();
        String approvalResult = outboundMaterialWrapper.getApprovalResult();
        String creator = userDetails.getUsername();
        System.out.println(outboundMaterialDTOS);
        for (OutboundMaterialDTO outboundMaterialDTO : outboundMaterialDTOS) {
            materialMapper.updateReviewOutboundById(outboundMaterialDTO);
        }
        HashMap<String, Object> variables = new HashMap<>();
        variables.put("approvalResult", approvalResult);
        org.activiti.engine.task.Task userTask = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .taskAssignee(creator) // 指定任务办理人
                .singleResult();
        System.out.println(userTask);
        if ("生产制造部部长审核".equals(userTask.getName())) {
            Authentication.setAuthenticatedUserId(userDetails.getNickName());
            taskService.addComment(userTask.getId(), processInstanceId, comment);
            taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(userTask.getId()).withVariables(variables).build());
        }
        return JsonResult.ok();
    }
    @ApiOperation(value = "领用人修改（删除）出库单物资")
    @Transactional
    @DeleteMapping("/outbound/{id}")
    public JsonResult deleteOutboundItemById(@PathVariable Integer id){
        materialMapper.deleteOutboundItemById(id);
        return JsonResult.ok();
    }

    @ApiOperation(value = "领用人修改（新增或者编辑）出库单物资")
    @Transactional
    @PutMapping("/outbound/update_process_outbound")
    public JsonResult updateOutboundItem(@RequestBody List<OutboundMaterialDTO> outboundMaterialDTOS,@AuthenticationPrincipal CustomUserDetails userDetails){
        String processInstanceId = null;
        String serialNumber = null;
        String positionName = null;
        String createBy = null;
        Date createTime = null;
        String recipient = null;
        String reviewer = null;
        String status = null;
        for (OutboundMaterialDTO outboundMaterialDTO : outboundMaterialDTOS) {
            if (outboundMaterialDTO.getProcessInstanceId() != null) {
                processInstanceId = outboundMaterialDTO.getProcessInstanceId();
                serialNumber = outboundMaterialDTO.getSerialNumber();
                positionName = outboundMaterialDTO.getPositionName();
                createBy = outboundMaterialDTO.getCreateBy();
                createTime = outboundMaterialDTO.getCreateTime();
                recipient = outboundMaterialDTO.getRecipient();
                status = outboundMaterialDTO.getStatus();
                break;
            }
        }
        int i = materialPositionMapper.selectPositionIdByName(positionName);
        for (OutboundMaterialDTO outboundMaterialDTO : outboundMaterialDTOS) {
            if(outboundMaterialDTO.getId() != null){
                materialMapper.updateOutboundItem(outboundMaterialDTO);
            }else {
                outboundMaterialDTO.setProcessInstanceId(processInstanceId);
                outboundMaterialDTO.setSerialNumber(serialNumber);
                outboundMaterialDTO.setPositionId(i);
                outboundMaterialDTO.setCreateTime (createTime);
                outboundMaterialDTO.setCreateBy(createBy);
                outboundMaterialDTO.setRecipient(recipient);
                outboundMaterialDTO.setStatus(status);
                materialMapper.applyOutbound(outboundMaterialDTO);
            }
        }
        System.out.println(outboundMaterialDTOS);
        Page<Task> tasks = taskRuntime.tasks(
                Pageable.of(0, 50), // 取足够多，防止有多个并行任务
                TaskPayloadBuilder
                        .tasks()
                        .withProcessInstanceId(processInstanceId)
                        .build()
        );
        Task currentTask = null;
        for (Task task : tasks.getContent()) {
            if ("修改出库申请".equals(task.getName()) && userDetails.getUsername().equals(task.getAssignee())) {
                currentTask = task;
                break;
            }
        }
        taskRuntime.complete(TaskPayloadBuilder.complete()
                .withTaskId(currentTask.getId())
                .build());
        return JsonResult.ok();
    }

    @ApiOperation(value = "保管员出库")
    @Transactional
    @PostMapping("/executeOutbound")
    public JsonResult executeOutbound(@RequestBody OutboundMaterialWrapper outboundMaterialWrapper,
                                      @AuthenticationPrincipal CustomUserDetails userDetails) {
        System.out.println(outboundMaterialWrapper);
        List<OutboundMaterialDTO> outboundMaterialDTOS = outboundMaterialWrapper.getOutboundMaterialDTOS();
        String comment = outboundMaterialWrapper.getApprovalCommentDTO().getComment();
        String processInstanceId = outboundMaterialDTOS.get(0).getProcessInstanceId();
        String creator = userDetails.getUsername();

        for (OutboundMaterialDTO outboundMaterialDTO : outboundMaterialDTOS) {
            materialMapper.updateCustodianOutboundById(outboundMaterialDTO);
            String code = outboundMaterialDTO.getCode();
            String serialNumber = outboundMaterialDTO.getSerialNumber();
            int number = outboundMaterialDTO.getNumber(); // 前端传来的出库数量
            materialMapper.updateMaterialStockByCodeAndNumber(code, number); // 直接传递数量参数
            materialMapper.updateOutboundStatus(serialNumber, "已完成");
        }
        org.activiti.engine.task.Task userTask = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .taskAssignee(creator)
                .singleResult();

        if (userTask != null && "保管人出库".equals(userTask.getName())) {
            Authentication.setAuthenticatedUserId(userDetails.getNickName());
            taskService.addComment(userTask.getId(), processInstanceId, comment);
            taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(userTask.getId()).build());
        }
        return JsonResult.ok();
    }

    @ApiOperation(value = "打印出库单")
    @PostMapping("/outbound/print/{processInstanceId}")
    public JsonResult print(@PathVariable String processInstanceId) {
        List<PrintOutboundVO> printOutboundVOS = materialMapper.selectPrintOutboundById(processInstanceId);
        return JsonResult.ok(printOutboundVOS);
    }

    @ApiOperation(value = "选中物资出入库记录")
    @GetMapping("/record/{code}")
    public JsonResult selectRecordsByCode(@PathVariable String code) {
        List<MaterialRecordVO> materialRecordVOS = materialMapper.selectMaterialRecordByCode(code);
        return JsonResult.ok(materialRecordVOS);
    }

    @ApiOperation(value = "更改物资信息")
    @PostMapping("/updateMaterialItem")
    public JsonResult updateMaterialItemByCode(@RequestBody MaterialDTO materialDTO) {
        materialMapper.updateMaterialItem(materialDTO);
        return JsonResult.ok();
    }

    @ApiOperation(value = "当前用户入库申请记录")
    @GetMapping("/warehousing_process")
    public JsonResult selectWarehousingProcess(@AuthenticationPrincipal CustomUserDetails userDetails) {
        List<MaterialProcessVO> materialProcessVOS = materialMapper.selectWarehousingProcessVO(userDetails.getNickName());
        System.out.println(materialProcessVOS);
        return JsonResult.ok(materialProcessVOS);
    }

    @ApiOperation(value = "当前用户出库申请记录")
    @GetMapping("/outbound_process")
    public JsonResult selectOutboundProcess(@AuthenticationPrincipal CustomUserDetails userDetails) {
        List<MaterialProcessVO> materialProcessVOS = materialMapper.selectOutboundProcessVO(userDetails.getNickName());
        System.out.println(materialProcessVOS);
        return JsonResult.ok(materialProcessVOS);
    }

    @ApiOperation(value = "全部入库申请记录")
    @GetMapping("/all_warehousing_process")
    public JsonResult selectAllWarehousingProcess() {
        List<MaterialProcessVO> materialProcessVOS = materialMapper.selectAllWarehousingProcessVO();
        System.out.println(materialProcessVOS);
        return JsonResult.ok(materialProcessVOS);
    }

    @ApiOperation(value = "全部出库申请记录")
    @GetMapping("/all_outbound_process")
    public JsonResult selectAllOutboundProcess() {
        List<MaterialProcessVO> materialProcessVOS = materialMapper.selectAllOutboundProcessVO();
        System.out.println(materialProcessVOS);
        return JsonResult.ok(materialProcessVOS);
    }
}
